-----------------------------------------------
-- Project		: ECE 251 FINAL PROJECT
-- Author 		: Mahmut Yilmaz
-- Last Modified: 04/12/2007
-----------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE work.all;

ENTITY lfsr IS
	PORT (	clock			: IN  STD_LOGIC;	-- PosEdge Clock used	
			reset			: IN  STD_LOGIC;	-- Resets all flops to 0, active HIGH
      		q	 			: OUT STD_LOGIC_VECTOR(31 DOWNTO 0); -- output pseudo-random number
			polynomial		: IN  STD_LOGIC_VECTOR(30 DOWNTO 0); -- set LFSR polynomial
																 -- it is recommended to set shift_enable='0'
																 -- before changing the polynomial
			seed 			: IN  STD_LOGIC_VECTOR(31 DOWNTO 0); -- seed to LFSR
																 -- it is recommended to set shift_enable='0'
																 -- before changing the polynomial
			seed_change		: IN  STD_LOGIC;	-- Enable seed change. Resets all flops first.
			shift_enable	: IN  STD_LOGIC 	-- Enable shift & pseudo-random number generation, active HIGH
			);
END lfsr;

ARCHITECTURE struct OF lfsr IS
	COMPONENT one_bit_block 
		PORT (	xor_in0			: IN  STD_LOGIC;	-- XOR input from feedback line	
				mux_sel			: IN  STD_LOGIC;	-- Multiplexer select
				flop_in			: IN  STD_LOGIC;	-- D flop input
				flop_clock		: IN  STD_LOGIC;	-- PosEdge Clock used	
				flop_reset		: IN  STD_LOGIC;	-- Resets the flop to 0, active HIGH
				flop_set		: IN  STD_LOGIC;	-- Sets the flop to 1, active HIGH
				lfsr_out		: OUT STD_LOGIC; 	-- Output as an LFSR output bit
	      		output_next		: OUT STD_LOGIC 	-- Output: input to next stage
				);
	END COMPONENT;
	
	COMPONENT dflop IS
		PORT (	clock			: IN  STD_LOGIC;	-- PosEdge Clock used	
				reset			: IN  STD_LOGIC;	-- Resets the flop to 0, active HIGH
				set				: IN  STD_LOGIC;	-- Sets the flop to 1, active HIGH
				input			: IN  STD_LOGIC;	-- Flop input
	      		q	 			: OUT STD_LOGIC 	-- Flop output
				);	
	END COMPONENT;
	
	COMPONENT g_and2 IS
		PORT (	in0,in1			: IN  STD_LOGIC;	-- AND inputs	
	      		q	 			: OUT STD_LOGIC 	-- AND output
				);
	END COMPONENT;
	
	COMPONENT g_and3 IS
		PORT (	in0,in1,in2		: IN  STD_LOGIC;	-- AND inputs	
	      		q	 			: OUT STD_LOGIC 	-- AND output
				);
	END COMPONENT;

	COMPONENT g_xor2 IS
		PORT (	in0,in1			: IN  STD_LOGIC;	-- XOR inputs	
	      		q	 			: OUT STD_LOGIC 	-- XOR output
				);
	END COMPONENT;
	
	COMPONENT g_inv IS
		PORT (	in0 			: IN  STD_LOGIC;	-- INV input
	      		q	 			: OUT STD_LOGIC 	-- INV output
				);
	END COMPONENT;
	
	SIGNAL inter_states : STD_LOGIC_VECTOR(31 DOWNTO 0);
	SIGNAL seed_enabled : STD_LOGIC_VECTOR(31 DOWNTO 0);
	SIGNAL clock_enabled: STD_LOGIC;
	SIGNAL seed_change_inverted: STD_LOGIC;
BEGIN
	-- Invert seed_change
	seed_change_inverted <= NOT seed_change;
	-- Create an enabled clock
	-- No clock toggling if shift_enable is '0' or seed_change is high
	clock_enabled <= shift_enable AND clock AND seed_change_inverted;
	-- Generate enabled seeds
	seed_enabled(0) <= seed_change AND seed(0);
	seed_enabled(1) <= seed_change AND seed(1);
	seed_enabled(2) <= seed_change AND seed(2);
	seed_enabled(3) <= seed_change AND seed(3);
	seed_enabled(4) <= seed_change AND seed(4);
	seed_enabled(5) <= seed_change AND seed(5);
	seed_enabled(6) <= seed_change AND seed(6);
	seed_enabled(7) <= seed_change AND seed(7);
	seed_enabled(8) <= seed_change AND seed(8);
	seed_enabled(9) <= seed_change AND seed(9);
	seed_enabled(10) <= seed_change AND seed(10);
	seed_enabled(11) <= seed_change AND seed(11);
	seed_enabled(12) <= seed_change AND seed(12);
	seed_enabled(13) <= seed_change AND seed(13);
	seed_enabled(14) <= seed_change AND seed(14);
	seed_enabled(15) <= seed_change AND seed(15);
	seed_enabled(16) <= seed_change AND seed(16);
	seed_enabled(17) <= seed_change AND seed(17);
	seed_enabled(18) <= seed_change AND seed(18);
	seed_enabled(19) <= seed_change AND seed(19);
	seed_enabled(20) <= seed_change AND seed(20);
	seed_enabled(21) <= seed_change AND seed(21);
	seed_enabled(22) <= seed_change AND seed(22);
	seed_enabled(23) <= seed_change AND seed(23);
	seed_enabled(24) <= seed_change AND seed(24);
	seed_enabled(25) <= seed_change AND seed(25);
	seed_enabled(26) <= seed_change AND seed(26);
	seed_enabled(27) <= seed_change AND seed(27);
	seed_enabled(28) <= seed_change AND seed(28);
	seed_enabled(29) <= seed_change AND seed(29);
	seed_enabled(30) <= seed_change AND seed(30);
	seed_enabled(31) <= seed_change AND seed(31);
	
	-- one_bit_block group
	bit_block_0: one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(0),
		flop_in=>inter_states(31),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(0),lfsr_out=>q(0),output_next=>inter_states(0));
	bit_block_1:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(1),
		flop_in=>inter_states(0),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(1),lfsr_out=>q(1),output_next=>inter_states(1));
	bit_block_2:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(2),
		flop_in=>inter_states(1),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(2),lfsr_out=>q(2),output_next=>inter_states(2));
	bit_block_3:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(3),
		flop_in=>inter_states(2),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(3),lfsr_out=>q(3),output_next=>inter_states(3));
	bit_block_4:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(4),
		flop_in=>inter_states(3),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(4),lfsr_out=>q(4),output_next=>inter_states(4));
	bit_block_5:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(5),
		flop_in=>inter_states(4),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(5),lfsr_out=>q(5),output_next=>inter_states(5));
	bit_block_6:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(6),
		flop_in=>inter_states(5),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(6),lfsr_out=>q(6),output_next=>inter_states(6));
	bit_block_7:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(7),
		flop_in=>inter_states(6),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(7),lfsr_out=>q(7),output_next=>inter_states(7));
	bit_block_8:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(8),
		flop_in=>inter_states(7),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(8),lfsr_out=>q(8),output_next=>inter_states(8));
	bit_block_9:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(9),
		flop_in=>inter_states(8),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(9),lfsr_out=>q(9),output_next=>inter_states(9));
	bit_block_10:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(10),
		flop_in=>inter_states(9),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(10),lfsr_out=>q(10),output_next=>inter_states(10));
	bit_block_11:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(11),
		flop_in=>inter_states(10),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(11),lfsr_out=>q(11),output_next=>inter_states(11));
	bit_block_12:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(12),
		flop_in=>inter_states(11),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(12),lfsr_out=>q(12),output_next=>inter_states(12));
	bit_block_13:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(13),
		flop_in=>inter_states(12),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(13),lfsr_out=>q(13),output_next=>inter_states(13));
	bit_block_14:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(14),
		flop_in=>inter_states(13),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(14),lfsr_out=>q(14),output_next=>inter_states(14));
	bit_block_15:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(15),
		flop_in=>inter_states(14),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(15),lfsr_out=>q(15),output_next=>inter_states(15));
	bit_block_16:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(16),
		flop_in=>inter_states(15),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(16),lfsr_out=>q(16),output_next=>inter_states(16));
	bit_block_17:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(17),
		flop_in=>inter_states(16),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(17),lfsr_out=>q(17),output_next=>inter_states(17));
	bit_block_18:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(18),
		flop_in=>inter_states(17),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(18),lfsr_out=>q(18),output_next=>inter_states(18));
	bit_block_19:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(19),
		flop_in=>inter_states(18),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(19),lfsr_out=>q(19),output_next=>inter_states(19));
	bit_block_20:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(20),
		flop_in=>inter_states(19),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(20),lfsr_out=>q(20),output_next=>inter_states(20));
	bit_block_21:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(21),
		flop_in=>inter_states(20),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(21),lfsr_out=>q(21),output_next=>inter_states(21));
	bit_block_22:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(22),
		flop_in=>inter_states(21),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(22),lfsr_out=>q(22),output_next=>inter_states(22));
	bit_block_23:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(23),
		flop_in=>inter_states(22),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(23),lfsr_out=>q(23),output_next=>inter_states(23));
	bit_block_24:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(24),
		flop_in=>inter_states(23),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(24),lfsr_out=>q(24),output_next=>inter_states(24));
	bit_block_25:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(25),
		flop_in=>inter_states(24),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(25),lfsr_out=>q(25),output_next=>inter_states(25));
	bit_block_26:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(26),
		flop_in=>inter_states(25),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(26),lfsr_out=>q(26),output_next=>inter_states(26));
	bit_block_27:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(27),
		flop_in=>inter_states(26),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(27),lfsr_out=>q(27),output_next=>inter_states(27));
	bit_block_28:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(28),
		flop_in=>inter_states(27),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(28),lfsr_out=>q(28),output_next=>inter_states(28));
	bit_block_29:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(29),
		flop_in=>inter_states(28),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(29),lfsr_out=>q(29),output_next=>inter_states(29));
	bit_block_30:  one_bit_block PORT MAP ( xor_in0=>inter_states(31),mux_sel=>polynomial(30),
		flop_in=>inter_states(29),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(30),lfsr_out=>q(30),output_next=>inter_states(30));
	
	-- the last flop
	last_flop: dflop PORT MAP (clock=>clock_enabled,reset=>reset,set=>seed_enabled(31),
		input=>inter_states(30),q=>inter_states(31));	
		
	q(31) <= inter_states(31);
	
END struct;


